#include "rule.hh"
#include "rating.hh"

#include <string>
#include <memory>
#include <iostream>
#include <tuple>

auto AcceptRule::result(Rating* rating) -> std::tuple<RuleResult, std::string> const
{
    return std::make_tuple(RuleResult::Accept, "");
} 

void AcceptRule::print() const
{
    std::cout << 'A' << std::endl;
}

auto RejectRule::result(Rating* rating) -> std::tuple<RuleResult, std::string> const
{
    return std::make_tuple(RuleResult::Reject, "");
}

void RejectRule::print() const
{
    std::cout << 'R' << std::endl;
}

auto JudgmentRule::result(Rating* rating) -> std::tuple<RuleResult, std::string> const
{
    // Get value
    int value {rating->attr(this->_attr)};

    // Compare
    switch (this->_oper)
    {
        case RuleOpertion::Greater: 
        {
            if (value > this->_value)
            {
                return std::make_tuple(RuleResult::Jump, this->_workflow);
            }
            else
                return std::make_tuple(RuleResult::Next, "");
        }
        case RuleOpertion::Less:
        {
            if (value < this->_value) 
                return std::make_tuple(RuleResult::Jump, this->_workflow);
            else
                return std::make_tuple(RuleResult::Next, "");
        }
    }
    return std::make_tuple(RuleResult::Reject, "");
}

void JudgmentRule::print() const
{
    std::cout << this->_attr;
    std::cout << ((this->_oper == RuleOpertion::Greater) ? '>' : '<');
    std::cout << this->_value;
    std::cout << ':' << this->_workflow << std::endl;
}

auto JumpRule::result(Rating* rating) -> std::tuple<RuleResult, std::string> const
{
    return std::make_tuple(RuleResult::Jump, this->_workflow);
}

void JumpRule::print() const
{
    std::cout << this->_workflow << std::endl;
}

std::unique_ptr<Rule> makeRule(std::string content)
{
    // a<2006:qkq
    // A
    // R
    // rfg
    // if (content.size() == 1)
    // {
    //     if (content.front() == 'A') 
    //         return std::make_unique<AcceptRule>();
    //     else if (content.front() == 'R') 
    //         return std::make_unique<RejectRule>();
    //     else
    //         return std::make_unique<JumpRule>(std::move(content));
    // }

    std::size_t colonPos {content.find(':')};
    if (colonPos == std::string::npos)
    {
        return std::make_unique<JumpRule>(std::move(content));
    }
    else
    {
        char attr {content[0]};
        RuleOpertion oper {
            content[1] == '>' ? RuleOpertion::Greater : RuleOpertion::Less
        };
        int value {std::stoi(&(content[2]))};
        std::string workflow {content.substr(colonPos + 1, content.size() - colonPos - 1)};
        
        return std::make_unique<JudgmentRule>(
            attr, oper, value, std::move(workflow)
        );
    }
}